package benchmarks;

//TODO nu deserializeren we dmv read/write-ClassAndObject --> zoek een manier om de andere soorten ook eens te testen! + eigl zijn veel registers onnodig
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import org.objenesis.strategy.SerializingInstantiatorStrategy;
import org.objenesis.strategy.StdInstantiatorStrategy;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.FieldSerializer;
import com.esotericsoftware.kryo.serializers.JavaSerializer;

import edu.vub.at.objects.ATObject;
import edu.vub.at.objects.natives.NATObject;
import edu.vub.at.objects.natives.NATTable;
import edu.vub.at.objects.natives.NATText;
import edu.vub.at.objects.natives.NATTypeTag;
import edu.vub.at.objects.natives.OBJLexicalRoot;
import edu.vub.at.objects.natives.grammar.AGAssignField;
import edu.vub.at.objects.natives.grammar.AGClosureLiteral;
import edu.vub.at.objects.natives.grammar.AGMessageSend;
import edu.vub.at.objects.natives.grammar.AGMethodInvocationCreation;
import edu.vub.at.objects.natives.grammar.AGSplice;
import edu.vub.at.objects.natives.grammar.AGSymbol;
import edu.vub.at.parser.NATParser;

public class KryoLib implements TestMethods {
	
	public static Kryo kryo;

	public KryoLib() {
		
		kryo = new Kryo();
		kryo.register(AGClosureLiteral.class).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(AGClosureLiteral.class));
		kryo.register(AGMessageSend.class).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(AGMessageSend.class));
//		kryo.register(AGMethodInvocationCreation.class).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(AGMethodInvocationCreation.class));
		kryo.register(NATTable.class).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(NATTable.class));
		//kryo.register(NATTable.EMPTY.getClass()).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(NATTable.EMPTY.getClass()));

		//kryo.register(OBJLexicalRoot.class).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(OBJLexicalRoot.class));

		kryo.register(AGSplice.class).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(AGSplice.class));
		kryo.register(NATTypeTag.class).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(NATTypeTag.class));
		
		kryo.register(
				NATTable.EMPTY.getClass(),
				new FieldSerializer(
						kryo,
						NATTable.EMPTY.getClass()) {
					@Override
					protected Object create(Kryo kryo, Input input,
							Class type) {
						return NATTable.EMPTY;
					}
				});
		
		kryo.register( 
				OBJLexicalRoot.class,
				new FieldSerializer(
						kryo,
						OBJLexicalRoot.class) {
					@Override
					protected Object create(Kryo kryo, Input input,
							Class type) {
						return OBJLexicalRoot._INSTANCE_;
					}
				});
		
		try {
			kryo.register(Class.forName("edu.vub.at.eval.PartialBinder$4")).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(Class.forName("edu.vub.at.eval.PartialBinder$4")));

			kryo.register(Class.forName("edu.vub.at.eval.PartialBinder$7")).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(Class.forName("edu.vub.at.eval.PartialBinder$7")));
			kryo.register(Class.forName("edu.vub.at.objects.natives.NATNil$2")).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(Class.forName("edu.vub.at.objects.natives.NATNil$2")));

			kryo.register(Class.forName("edu.vub.at.objects.natives.NATNil$3")).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(Class.forName("edu.vub.at.objects.natives.NATNil$3")));
			kryo.register(Class.forName("edu.vub.at.objects.natives.NATNil$4")).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(Class.forName("edu.vub.at.objects.natives.NATNil$4")));
			kryo.register(Class.forName("edu.vub.at.objects.natives.NATNil$5")).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(Class.forName("edu.vub.at.objects.natives.NATNil$5")));

			//kryo.register(Class.forName("edu.vub.at.objects.natives.OBJLexicalRoot$1")).setInstantiator(new StdInstantiatorStrategy().newInstantiatorOf(Class.forName("edu.vub.at.objects.natives.OBJLexicalRoot$1")));
		
			kryo.register( //TODO is deze nodig? Vanwaar komt $1 nu net???
					Class.forName("edu.vub.at.objects.natives.OBJLexicalRoot$1"),
					new FieldSerializer(
							kryo,
							Class.forName("edu.vub.at.objects.natives.OBJLexicalRoot$1")) {
						@Override
						protected Object create(Kryo kryo, Input input,
								Class type) {
							return OBJLexicalRoot._INSTANCE_;
						}
					});
		
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	

	@Override
	public byte[] serialize(Object o) throws IOException {
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		Output out = new Output(buffer);
		kryo.writeClassAndObject(out, o);
		out.flush();
		out.close();
		return buffer.toByteArray();
	}

	@Override
	public Object deserialize(byte[] b, Class c) throws IOException,
			ClassNotFoundException {
		ByteArrayInputStream in = new ByteArrayInputStream(b);
		Input input = new Input(in);
		return kryo.readClassAndObject(input);
	}
	
	@Override
	public Object copy(Object o) throws IOException, ClassNotFoundException {
		return deserialize(serialize(o), o.getClass());
	}

	public Object copyFast(Object o) throws IOException, ClassNotFoundException {
		return kryo.copy(o);
	}	
	

}
